/*
9.27
1.function matrix_calc_taskA,matrix_calc_taskB
2."N" means iteration times
10.2
1.merge the for loop in taskB
2.move memory access variable out of "for loop".
*/
#ifndef _CALC_H_
#define _CALC_H_
//#ifndef _GNU_SOURCE
//#define _GNU_SOURCE
//#include<iostream>
#include <sched.h>
#include <pthread.h>
//using namespace std;
#ifdef __cplusplus
extern "C"{	
#endif

typedef struct {
	int* 			rowArray;
	const int* 		rowOffset;
	int 			rowArraySize;
	const int* 		columnIndice;
	const double* 	S;
	const double*	valueNormalMatrix;
	double* 		Id;
}TaskMatrixInfoA;

typedef struct {
	const double * 	valueSpiceMatrix;//N*2
	const int* 		rowOffset; 		//n+1
	const int* 		columnIndice; 	//N

	double* 		A;	//N
	double*		 	S;	//nx1
	double*			R;	//nx1
	double* 		H;	//nx1
	const double* 	D;	//N*2
	double* 		IC;	//nx1
	double* 		IG;	//nx1
	double 		alpha;
	int * 			rowArray; //kx1
	int 			rowArraySize;
	void* 			hdl;  //? what's this?
}TaskMatrixInfoB;


typedef struct {
	int n1;
	int n2;
	TaskMatrixInfoA ** listDataList;
}MY_ARGSA;


void* mysuma(void* args){
	MY_ARGSA* my_args = (MY_ARGSA*) args;
	int n1 = my_args->n1;
	int n2 = my_args->n2;
	TaskMatrixInfoA **listDataList = my_args->listDataList;

	for (int i = n1 ;i < n2; ++i)
	{	
		int row_array_size= listDataList[i]->rowArraySize;	
		TaskMatrixInfoA * list_Data_List=listDataList[i];
		const double *valueNormalMatrix = list_Data_List->valueNormalMatrix;
		const double *S = list_Data_List->S;
		const int *columnIndice = list_Data_List->columnIndice;
		for (unsigned int it = 0; it < row_array_size; ++it	)
		{
			const int node = list_Data_List->rowArray[it];
			int colum_num = list_Data_List->rowOffset[node + 1];
			double tmp=0;
			for (int j = list_Data_List->rowOffset[node];j < colum_num;++j)
			{
				tmp += valueNormalMatrix[j]*S[columnIndice[j]];
			}
			list_Data_List->Id[node]+=tmp;
		}
	}
	return NULL;
}

typedef struct {
	int n1;
	int n2;
	TaskMatrixInfoB ** listDataList;
}MY_ARGSB;


void* mysumb(void* args){
	MY_ARGSB* my_args = (MY_ARGSB*) args;
	int n1 = my_args->n1;
	int n2 = my_args->n2;
	TaskMatrixInfoB **listDataList = my_args->listDataList;

	for (int i = n1;i<n2;i++){
		TaskMatrixInfoB * list_Data_List = listDataList[i];
		int row_array_size = list_Data_List->rowArraySize;
		const double alpha = list_Data_List->alpha;
		double* A = list_Data_List->A;
		const double* S = list_Data_List->S;
		const int* columnIndice=list_Data_List->columnIndice;
		const double* valueSpiceMatrix=list_Data_List->valueSpiceMatrix;

		for(int it = 0;it < row_array_size;++it)
		{
			int row = list_Data_List->rowArray[it];
			const int k1 = row << 1;
			int colum_num = list_Data_List->rowOffset[row + 1];
										
			double ig_tmp=0;
			double ic_tmp=0;
			
		//	cout<<colum_num-list_Data_List->rowOffset[row]<<" ";
			for (int p = list_Data_List->rowOffset[row];p < colum_num;++p){
				const int k = p << 1;
				double cond =valueSpiceMatrix[k];
				double cap  =valueSpiceMatrix[k+1];					
				ig_tmp += cond * S[columnIndice[p]];
				ic_tmp += cap * S[columnIndice[p]];
				//(9)
				A[p] = cond +  cap * alpha;
			}
 			//(7)(8)
 			list_Data_List->IG[row] +=ig_tmp; 
 			list_Data_List->IC[row] +=ic_tmp; 
			list_Data_List->R[row] = list_Data_List->D[k1]-ig_tmp;
			list_Data_List->H[row] = list_Data_List->D[k1+1]-ic_tmp;
		} 
	}
	return NULL;
}


#define THREAD_NUM 32
void matrix_calc_taskA(TaskMatrixInfoA** listDataList,int N)
{
	int thread_num = THREAD_NUM;
	pthread_t th[thread_num];

	int i;
	int mid = N/thread_num;
	MY_ARGSA args[thread_num];
	for(i =0;i<thread_num-1;i++){
		args[i].n1 = i*mid;
		args[i].n2 = (i+1)*mid;
		args[i].listDataList = listDataList;
	}

	args[thread_num-1].n1 = i*mid; 
	args[thread_num-1].n2 = N;
	args[thread_num-1].listDataList = listDataList;

	//设置亲和性
	int blist[20]={1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39};
	cpu_set_t cpu_info1,cpu_info2,mask1;
	CPU_ZERO(&cpu_info1);
	CPU_ZERO(&cpu_info2);
	CPU_ZERO(&mask1);
	for(i =0;i<20;i++){		
		CPU_SET(blist[i],&cpu_info1);
		CPU_SET(blist[i]-1,&cpu_info2);
	}
	CPU_SET(3,&mask1);	
	sched_setaffinity(0, sizeof(cpu_set_t), &mask1);	
	//产生线程	
	for(i =0;i<thread_num;i++){
		pthread_create(&th[i],NULL,mysuma,&args[i]);	
	}
	//绑核
	for(i =0;i<thread_num/2;i++){
		pthread_setaffinity_np(th[i], sizeof(cpu_set_t), &cpu_info1);
	}
	for(i = thread_num/2;i<thread_num;i++){
		pthread_setaffinity_np(th[i], sizeof(cpu_set_t), &cpu_info2);
	}

	for(i =0;i<thread_num;i++){
		pthread_join(th[i],NULL);
	}
}

//Task B interface
void matrix_calc_taskB(TaskMatrixInfoB** listDataList,int N)
{
	int thread_num = THREAD_NUM;
	pthread_t th[thread_num];

	int i;
	int mid = N/thread_num;
	MY_ARGSB args[thread_num] ;
	for(i =0;i<thread_num-1;i++){
		args[i].n1 = i*mid;
		args[i].n2 = (i+1)*mid;
		args[i].listDataList = listDataList;
	}

	args[thread_num-1].n1 = i*mid; 
	args[thread_num-1].n2 = N;
	args[thread_num-1].listDataList = listDataList;

	int blist[20]={1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,33,35,37,39};
	cpu_set_t cpu_info1,cpu_info2;
	CPU_ZERO(&cpu_info1);
	CPU_ZERO(&cpu_info2);
	for(i =0;i<20;i++){		
		CPU_SET(blist[i],&cpu_info1);
		CPU_SET(blist[i]-1,&cpu_info2);
	}		
	
	for(i =0;i<thread_num;i++){
		pthread_create(&th[i],NULL,mysumb,&args[i]);	
	}
//绑核
	for(i =0;i<thread_num/2;i++){
		pthread_setaffinity_np(th[i], sizeof(cpu_set_t), &cpu_info1);
	}
	for(i = thread_num/2;i<thread_num;i++){
		pthread_setaffinity_np(th[i], sizeof(cpu_set_t), &cpu_info2);
	}

	for(i =0;i<thread_num;i++){
		pthread_join(th[i],NULL);
	}
	
}

#ifdef __cplusplus
}
#endif

#endif
